#include "CManagerTags.h"

CManagerTags::CManagerTags(){
	this->tagManager = new CManagerTag(static_cast<IObservadorTag*>(this));
	this->cargarTags();
	this->buscarMenorId();
}

CManagerTags::~CManagerTags(){
	this->guardarTags();
	delete(tagManager);
}

void CManagerTags::cargarTags(){
	this->stream.open(DB_TAGS, std::ios::in | std::ios::binary | std::ios::out | std::ios::ate );
	if(this->stream.is_open()){

		this->stream.clear();
		this->stream.seekg(0,std::ios::beg);
		while((!this->stream.eof())&&(this->stream.peek()!=std::ios::traits_type::eof())){
			
			DBFrecuencias::Offset offset = this->stream.tellg();
			this->stream.seekg(offset);//esta linea no haria falta, pero a veces se pone de la gorra
			bool borrado=false;
			unsigned int longitud;
			this->stream.read(reinterpret_cast<char*>(&borrado),sizeof(bool));
			this->stream.read(reinterpret_cast<char*>(&longitud),sizeof(unsigned int));
			DBFrecuencias::STag sTag;
			if(!borrado){
				//si no esta borrado el registro, cargo todos los datos
				std::string id;				
				char* buffer = new char[longitud+1];
				this->stream.read(reinterpret_cast<char*>(buffer),longitud);
				buffer[longitud] = '\0';
				id.assign(buffer);
				delete[] buffer;
				this->stream.read(reinterpret_cast<char*>(&sTag),sizeof(DBFrecuencias::STag));
				sTag.offset = offset;
				this->indice.insert(std::pair<std::string,DBFrecuencias::STag>(id,sTag));
				this->indiceAuxiliar.insert(std::pair<DBFrecuencias::TagId,std::string>(sTag.tagId,id));
			} else {
				
				this->stream.seekg(longitud + sizeof(DBFrecuencias::STag),std::ios::cur);								
			}
		}
	} else {
		this->stream.open(DB_TAGS, std::ios::binary | std::ios::out );
		this->stream.close();
		this->stream.open(DB_TAGS, std::ios::in | std::ios::binary | std::ios::out | std::ios::ate );
	}
	this->stream.clear();
}

void CManagerTags::guardarTags(){
//	this->stream.open(DB_TAGS, std::ios::out | std::ios::binary | std::ios::trunc);
//	if(this->stream.is_open()){
//		this->stream.clear();
//		this->stream.seekp(0,std::ios::beg);
//		DBFrecuencias::IndiceTag::iterator it = this->indice.begin();
//		for( ; it != this->indice.end() ; it++ ){
//			std::string nombreTag = it->first;
//			unsigned int longitud = nombreTag.size();
//			this->stream.write(reinterpret_cast<const char*>(&longitud),sizeof(unsigned int));
//			this->stream.write(nombreTag.c_str(),longitud);
//			DBFrecuencias::STag sTag = it->second;
//			this->stream.write(reinterpret_cast<const char*>(&sTag),sizeof(DBFrecuencias::STag));
//		}
//	}
	this->stream.close();
}
	
void CManagerTags::incrementarNumeroPalabras(DBFrecuencias::TagId tag, DBFrecuencias::Frecuencia frec){
	DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.find(tag);
	if(it != this->indiceAuxiliar.end()){
		DBFrecuencias::IndiceTag::iterator iter = this->indice.find(it->second);
		if(iter != this->indice.end()){
			DBFrecuencias::STag sTag = iter->second;
			sTag.numeroPalabras += frec;
			//haces el seek, pasando el bool, la longitud, y los caracteres para llegar a la estructura
			this->stream.seekp(sTag.offset + sizeof(bool) + sizeof(unsigned int) +
				((std::string)it->second).size(),std::ios::beg);
			this->stream.write(reinterpret_cast<const char*>(&sTag),sizeof(DBFrecuencias::STag));
			this->indice.erase(iter);
			this->indice.insert(std::pair<std::string,DBFrecuencias::STag>(it->second,sTag));
		}
	}
}
		
void CManagerTags::decrementarNumeroPalabras(DBFrecuencias::TagId tag, DBFrecuencias::Frecuencia frec){
	DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.find(tag);
	if(it != this->indiceAuxiliar.end()){
		DBFrecuencias::IndiceTag::iterator iter = this->indice.find(it->second);
		if(iter != this->indice.end()){
			DBFrecuencias::STag sTag = iter->second;
			if(sTag.numeroPalabras > frec){
				sTag.numeroPalabras -= frec;	
			} else {
				sTag.numeroPalabras = 0;
			}
			this->stream.seekp(sTag.offset + sizeof(bool) + sizeof(unsigned int) +
				((std::string)it->second).size(),std::ios::beg);
			this->stream.write(reinterpret_cast<const char*>(&sTag),sizeof(DBFrecuencias::STag));
			this->indice.erase(iter);
			this->indice.insert(std::pair<std::string,DBFrecuencias::STag>(it->second,sTag));
		}
	}	
}
	
DBFrecuencias::TagId CManagerTags::crearTag(const std::string& nombreTag){
	DBFrecuencias::TagId tagId = this->menorId;
	if(!this->existeTag(nombreTag)){
		DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.find(tagId);
		while(it != this->indiceAuxiliar.end()){
			it = this->indiceAuxiliar.find(++tagId);
		}
		DBFrecuencias::STag nuevoTag;
		nuevoTag.numeroPalabras = 0;
		nuevoTag.tagId = tagId;
		this->indiceAuxiliar.insert(std::pair<DBFrecuencias::TagId,std::string>(tagId,nombreTag));
		this->menorId = tagId + 1;
		this->tagManager->crearTag(tagId);
		// file
		this->stream.seekp(0,std::ios::end);
		nuevoTag.offset = this->stream.tellp();
		this->stream.seekp(0,std::ios::end);
		bool borrado = false;
		unsigned int longitud = nombreTag.size();
		this->stream.write(reinterpret_cast<const char*>(&borrado),sizeof(bool));
		this->stream.write(reinterpret_cast<const char*>(&longitud),sizeof(unsigned int));
		this->stream.write(nombreTag.c_str(),longitud);
		this->stream.write(reinterpret_cast<const char*>(&nuevoTag),sizeof(DBFrecuencias::STag));
		this->stream.flush();
		this->indice.insert(std::pair<std::string,DBFrecuencias::STag>(nombreTag,nuevoTag));				
		return tagId;
	} else {
		return YA_EXISTE_TAG;
	}
}
	
DBFrecuencias::TagId CManagerTags::consultarTag(const std::string& nombreTag){
	DBFrecuencias::IndiceTag::iterator it = this->indice.find(nombreTag);
	if(it != this->indice.end()){
		DBFrecuencias::STag sTag = it->second;
		return sTag.tagId;
	} else {
		return (DBFrecuencias::TagId)NO_EXISTE_TAG;
	}
}
	
void CManagerTags::eliminarTag(const std::string& nombreTag){
	if(this->existeTag(nombreTag)){
		DBFrecuencias::IndiceTag::iterator it = this->indice.find(nombreTag);
		this->eliminarTag(((DBFrecuencias::STag)(it->second)).tagId);
	}
}
	
void CManagerTags::eliminarTag(DBFrecuencias::TagId tagId){
	if(this->existeTag(tagId)){
		this->tagManager->eliminarTag(tagId);
		DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.find(tagId);
		std::string nombre = it->second;
		if(this->existeTag(nombre)){
			DBFrecuencias::IndiceTag::iterator iter = this->indice.find(nombre);
			if(this->menorId > tagId){
				this->menorId = tagId;
			}
			this->stream.seekp(((DBFrecuencias::STag)iter->second).offset,std::ios::beg);
			bool borrado = true;
			this->stream.write(reinterpret_cast<const char*>(&borrado),sizeof(bool));
			this->indice.erase(iter);
		}
		this->indiceAuxiliar.erase(it);
	}
}

bool CManagerTags::existeTag(std::string nombreTag){
	return (this->indice.find(nombreTag) != this->indice.end());
}

bool CManagerTags::existeTag(DBFrecuencias::TagId tagId){
	return (this->indiceAuxiliar.find(tagId) != this->indiceAuxiliar.end());
}

DBFrecuencias::ListaNombreTags CManagerTags::consultarListTags(){
	DBFrecuencias::ListaNombreTags tags;
	DBFrecuencias::IndiceTag::iterator it = this->indice.begin();
	for( ; it != this->indice.end() ; it++){
		tags.push_back(it->first);
	}
	return tags;
}

DBFrecuencias::Frecuencia CManagerTags::consultarNumeroPalabras(DBFrecuencias::TagId tagId){
	if(this->existeTag(tagId)){
		DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.find(tagId);
		std::string nombreTag = it->second;
		if(this->existeTag(nombreTag)){
			DBFrecuencias::IndiceTag::iterator iter = this->indice.find(nombreTag);
			DBFrecuencias::STag sTag = iter->second;
			return sTag.numeroPalabras;
		} 
	} 
	return NO_EXISTE_TAG;
}

DBFrecuencias::Frecuencia CManagerTags::consultarNumeroPalabras(const std::string& nombreTag){
	if(this->existeTag(nombreTag)){
		DBFrecuencias::IndiceTag::iterator iter = this->indice.find(nombreTag);
		DBFrecuencias::STag sTag = iter->second;
		return sTag.numeroPalabras;
	}
	return NO_EXISTE_TAG;
}

void CManagerTags::buscarMenorId(){
	this->menorId = 0;
	DBFrecuencias::AuxIndiceTag::iterator it = this->indiceAuxiliar.begin();
	for( ; it != this->indiceAuxiliar.end() ; it++){
		if( it->first == this->menorId ){
			this->menorId++;
		}
	}
}
